package assist.domain.model;

import java.io.Serializable;


import assist.domain.model.exception.InvalidGameTimeException;

/**
 * Represents the game time in a Game.  Provides methods for parsing different
 * game time representations into a GameTime object, as well as methods for 
 * retrieving the game time formatted with period/min/seconds elapsed, etc.
 */
public class GameTime implements Serializable
{
  
    private static final long serialVersionUID = 1L;
    
    private Integer period;
    private Integer minutes;
    private Integer seconds;
    
    /**
     * Public constructor for serialization, etc.
     */
    public GameTime(){}    
    
    /**
     * Private constructor used by factory methods.
     * @param period The period number in the game, as int.
     * @param minutes The elapsed minutes in the period as int.
     * @param seconds The elapsed seconds in the period as int.
     */
    private GameTime (final int period, final int minutes, 
            final int seconds)
    {           
        this.period = period;
        this.setTime(minutes, seconds);
    }

    /**
     * Creates a GameTime object given game time and period as Strings.
     * @param period The period number in the game, as String.
     * @param time The elapsed time (MM:ss) in the period as a String.
     * @return An integer representing the seconds elapsed in the game.
     */
    public static GameTime create(final String period, final String time)
    {
        final String [] splitTime = time.split(":");
        return GameTime.create(period, splitTime[0], splitTime[1]);
    }
    
    /**
     * Creates a GameTime object given game time as String and Period as Int.
     * @param period The period number in the game, as String.
     * @param time The elapsed time (MM:ss) in the period as a String.
     * @return An integer representing the seconds elapsed in the game.
     */
    public static GameTime create(final Integer period, final String time)
    {
        final String [] splitTime = time.split(":");
        return GameTime.create(period.toString(), splitTime[0], splitTime[1]);
    }      
    
    /**
     * Creates a GameTime object given the period, minutes and seconds
     * as Strings.
     * @param period The period number in the game, as String.
     * @param minutes The elapsed minutes in the period as a String.
     * @param seconds The elapsed seconds in the period as a String.
     * @return An integer representing the seconds elapsed in the game.
     */
    public static GameTime create(final String period, final String minutes, 
            final String seconds)
    {
        try
        {
            final int iPeriod = Integer.parseInt(period);
            final int iMinutes = Integer.parseInt(minutes);
            final int iSeconds = Integer.parseInt(seconds); 
            return GameTime.create(iPeriod, iMinutes, iSeconds);
        }
        catch (NumberFormatException exc)
        {
            throw new InvalidGameTimeException("Could not parse game time "
                + "period: " + period + " time:" + minutes + ":" + seconds,
                 exc);
        }        
    }    
    
    /**
     * Creates a GameTime object given game time and period as integers.
     * @param period The period number in the game, as String.
     * @param time The elapsed time (MM:ss) in the period as a String.
     * @return An integer representing the seconds elapsed in the game.
     */
    public static GameTime create(final int period, final int minutes, 
            final int seconds)
    {           
        return new GameTime(period, minutes, seconds);
    }
    
    /**
     * Sets the time, based on given minutes and seconds.
     * @param minutes
     * @param seconds
     * @throws InvalidGameTimeException if the number of seconds exceeds 60, 
     * or if the time is not between 0:00 and 20:00.
     */
    public void setTime(final int minutes, final int seconds)
    {
        if (minutes > 20 || seconds >= 60 || minutes < 0 || seconds < 0
                || (minutes == 20 && seconds > 0))
        {
            throw new InvalidGameTimeException("Game time must be between"
               + " 0:00 and 20:00");
        }
        this.minutes = minutes;
        this.seconds = seconds;
    }
    
    /**
     * Calculates the total number of seconds that have elapsed in the game,
     * based on the period and time.  Will be useful for calculating various
     * game time dependent statistics.
     * @return The total number of elapsed seconds in the game.
     */
    public Integer getElapsedSeconds()
    {
        return this.seconds + (this.minutes * 60) 
                + ((this.period - 1) * 20 * 60);   
    }
    
    /**
     * 
     * @return The period of this game time.
     */
    public Integer getPeriod()
    {
        return this.period;
    }
    
    /**
     * 
     * @return The minutes of this game time.
     */    
    public Integer getMinutes()
    {
        return this.minutes;
    }
    
    /**
     * 
     * @return The seconds of this game time.
     */    
    public Integer getSeconds()
    {
        return this.seconds;
    }    
}
